﻿using System;
using System.Collections.Generic;
using Dataweb.NShape.Advanced;
using Dataweb.NShape.WinFormsUI;
using Dataweb.NShape;
using System.Drawing;

namespace cz.zcu.PreSti.Shapes
{
    public class Symbols : ISymbols
    {
        private Diagram diagram;
        public Symbols(Diagram diagram)
        {
            this.diagram = diagram;
        }

        #region ISymbols Members

        public int GetSymbolsCount()
        {
            return diagram.Shapes.Count;
        }

        public List<ISymbol> GetEntryPoints()
        {
            List<ISymbol> entryPoints = new List<ISymbol>();
            foreach (Shape s in diagram.Shapes)
            {
                if (s.Type.FullName == "PreStiShapes.EntryPoint")
                {
                    entryPoints.Add((ISymbol)s);
                }

            }
            return entryPoints;
        }

        public List<ISymbol> GetExitPoints()
        {
            List<ISymbol> exitPoints = new List<ISymbol>();
            foreach (Shape s in diagram.Shapes)
            {
                if (s.Type.FullName == "PreStiShapes.ExitPoint")
                {
                    exitPoints.Add((ISymbol)s);
                }

            }
            return exitPoints;
        }

        public List<ISymbol> GetSetters()
        {
            List<ISymbol> setters = new List<ISymbol>();
            foreach (Shape s in diagram.Shapes)
            {
                if (s.Type.FullName == "PreStiShapes.Setter")
                {
                    setters.Add((ISymbol)s);
                }

            }
            return setters;
        }

        public List<ISymbol> GetGetters()
        {
            List<ISymbol> getters = new List<ISymbol>();
            foreach (Shape s in diagram.Shapes)
            {
                if (s.Type.FullName == "PreStiShapes.Getter")
                {
                    getters.Add((ISymbol)s);
                }

            }
            return getters;
        }

        public List<ITrigger> GetTriggers(ISymbol s)
        {
            List<ITrigger> t = new List<ITrigger>();
            foreach (ControlPointId cpi in ((Shape)s).GetControlPointIds(ControlPointCapabilities.Connect))
                foreach (ShapeConnectionInfo sci in ((Shape)s).GetConnectionInfos(cpi, null))
                    if (!sci.IsEmpty)
                        if (sci.OtherShape is ITrigger)
                        {
                            ITrigger trig = (ITrigger)(sci.OtherShape);
                            if (trig.IsDescendantConnected())
                            {
                                ISymbol descendant = trig.GetDescendant();
                                if (descendant is ISymbol && descendant != s)
                                    t.Add(trig);
                            }
                        }
            return t;
        }

        public List<IConnection> GetSetterConnections(ISymbol s)
        {
            List<IConnection> c = new List<IConnection>();
            foreach (ControlPointId cpi in ((Shape)s).GetControlPointIds(ControlPointCapabilities.Connect))
                if (IsControlPointSetter(s, cpi))
                    foreach (ShapeConnectionInfo sci in ((Shape)s).GetConnectionInfos(cpi, null))
                        if (!sci.IsEmpty)
                            if (sci.OtherShape is IConnection)
                            {
                                IConnection conn = (IConnection)(sci.OtherShape);
                                if (conn.IsFullyConnected() && conn.GetConnectedShape() is ISymbol)
                                    c.Add(conn);
                            }
            return c;
        }

        public String GetActualTooltipText(Point position, out Point tooltipPos)
        {
            int range = 3;
            tooltipPos = new Point();
            if (diagram.Shapes.Count > 0)
            {
                IEnumerable<Shape> shapes = diagram.Shapes.FindShapes(position.X, position.Y, ControlPointCapabilities.All, range);
                foreach (Shape s in shapes)
                {
                    ControlPointId cpi = s.HitTest(position.X, position.Y, ControlPointCapabilities.Connect, range);
                    if (cpi != ControlPointId.None && cpi != 0)
                    {
                        tooltipPos = new Point(s.GetControlPointPosition(cpi).X, s.GetControlPointPosition(cpi).Y + 22);
                        int pos = GetControlPointIndex(cpi);
                        if (pos < ((ISymbol)s).ActionsCount) return ((ISymbol)s).GetTitleForAction(pos);
                        pos -= ((ISymbol)s).ActionsCount;
                        if (pos < ((ISymbol)s).EventsCount) return ((ISymbol)s).GetTitleForEvent(pos);
                        pos -= ((ISymbol)s).EventsCount;
                        if (pos < ((ISymbol)s).SettersCount) return ((ISymbol)s).GetTitleForSetter(pos);
                        pos -= ((ISymbol)s).SettersCount;
                        if (pos < ((ISymbol)s).GettersCount) return ((ISymbol)s).GetTitleForGetter(pos);
                    }
                    else
                    {
                        return null;
                    }
                }
            }
            return null;
        }

        public String GetActualTooltipText(Point position)
        {
            Point p;
            return GetActualTooltipText(position, out p);
        }

        #endregion

        public static ControlPointId GetControlPointId(int index)
        {
            return index + 1;
        }


        public static int GetControlPointIndex(ControlPointId id)
        {
            return id - 1;
        }

        public static bool IsControlPointAction(ISymbol shape, ControlPointId id)
        {
            if (shape == null) return false;
            return
                GetControlPointIndex(id) >= 0 &&
                GetControlPointIndex(id) < shape.ActionsCount;
        }

        public static bool IsControlPointEvent(ISymbol shape, ControlPointId id)
        {
            if (shape == null) return false;
            return
                GetControlPointIndex(id) >= shape.ActionsCount &&
                GetControlPointIndex(id) < shape.ActionsCount + shape.EventsCount;
        }

        public static bool IsControlPointSetter(ISymbol shape, ControlPointId id)
        {
            if (shape == null) return false;
            return
                GetControlPointIndex(id) >= shape.ActionsCount + shape.EventsCount &&
                GetControlPointIndex(id) < shape.ActionsCount + shape.EventsCount + shape.SettersCount;
        }

        public static bool IsControlPointGetter(ISymbol shape, ControlPointId id)
        {
            if (shape == null) return false;
            return
                GetControlPointIndex(id) >= shape.ActionsCount + shape.EventsCount + shape.SettersCount &&
                GetControlPointIndex(id) < shape.ActionsCount + shape.EventsCount + shape.SettersCount + shape.GettersCount;
        }

        public static int ControlPointIdToActionN(ISymbol symbol, ControlPointId controlPointId)
        {
            if (controlPointId < 0 || controlPointId > symbol.ActionsCount)
                throw new IndexOutOfRangeException("ControlPointId does not belong to action");
            return GetControlPointIndex(controlPointId);
        }

        public static int ControlPointIdToEventN(ISymbol symbol, ControlPointId controlPointId)
        {
            if (controlPointId < symbol.ActionsCount || controlPointId > symbol.ActionsCount + symbol.EventsCount)
                throw new IndexOutOfRangeException("ControlPointId does not belong to event");
            return GetControlPointIndex(controlPointId) - symbol.ActionsCount;
        }

        public static int ControlPointIdToSetterN(ISymbol symbol, ControlPointId controlPointId)
        {
            if (controlPointId < symbol.ActionsCount + symbol.EventsCount || controlPointId > symbol.SettersCount + symbol.ActionsCount + symbol.EventsCount)
                throw new IndexOutOfRangeException("ControlPointId does not belong to setter");
            return GetControlPointIndex(controlPointId) - symbol.ActionsCount - symbol.EventsCount;
        }

        public static int ControlPointIdToGetterN(ISymbol symbol, ControlPointId controlPointId)
        {
            if (controlPointId < symbol.SettersCount + symbol.ActionsCount + symbol.EventsCount || controlPointId > symbol.SettersCount + symbol.ActionsCount + symbol.EventsCount + symbol.GettersCount)
                throw new IndexOutOfRangeException("ControlPointId does not belong to getter");
            return GetControlPointIndex(controlPointId) - symbol.SettersCount - symbol.ActionsCount - symbol.EventsCount;
        }

        public Diagram Diagram
        {
            get
            {
                return diagram;
            }
        }

        public void checkArrows(Display display)
        {
            foreach (Shape s in Diagram.Shapes)
            {
                if (s is IConnection)
                {
                    if (!((IConnection)s).IsFullyConnected())
                    {
                        s.Disconnect(-1);
                        s.Disconnect(-2);
                        Diagram.RemoveShapeFromLayers(s, LayerIds.All);
                        display.DeleteShape(s);
                    }
                }
                if (s is ITrigger)
                {
                    if (!((ITrigger)s).IsFullyConnected())
                    {
                        s.Disconnect(-1);
                        s.Disconnect(-2);
                        Diagram.RemoveShapeFromLayers(s, LayerIds.All);
                        display.DeleteShape(s);
                    }
                }
            }
        }

        public static void createTemplates(Project project)
        {
            foreach (ShapeType shapeType in project.ShapeTypes)
            {
                if (shapeType.LibraryName != "Core")
                {
                    Template template = new Template(shapeType.Name, shapeType.CreateInstance());
                    project.Repository.Insert(template);
                    try
                    {
                        ModelObjectBase modelObj = (ModelObjectBase)project.ModelObjectTypes[shapeType.FullName + "Model"].CreateInstance();
                        template.Shape.ModelObject = modelObj.Clone();
                        
                        int n = 1;
                        foreach (ControlPointId id in template.Shape.GetControlPointIds(ControlPointCapabilities.Connect | ControlPointCapabilities.Glue))
                        {
                            bool b = template.Shape.HasControlPointCapability(id, ControlPointCapabilities.Connect);

                            template.MapTerminal(n++, id);
                            bool c = b;
                        }
                        project.Repository.Update(template);
                        project.Repository.Insert(modelObj);
                    }
                    catch (ArgumentException) { }
                    
                }
            }
        }
    }
}